---
sidebar_position: 2
---

import Image from "@theme/IdealImage";
import Admonition from "@theme/Admonition";
import { HStack } from "@site/src/components/HStack";
import basicCalendar from "./assets/basic-calendar.png";
import basicCalendarList from "./assets/basic-calendar-list.png";
import dateRangeCalendarList from "./assets/date-range-calendar-list.png";
import twoCalendarsMounted from "./assets/two-calendars-mounted.png";
import customFormatting from "./assets/custom-formatting.png";
import customLocale from "./assets/custom-locale.png";
import disabledDates from "./assets/disabled-dates.png";
import compact from "./assets/calendar-list-compact.png";
import bottomSheetAndroid from "@site/static/videos/bottom-sheet-android.mp4";

# Usage

:::tip

All Flash Calendar props contain the word `calendar` to improve IDE autocompletion (e.g. `calendarMinDateId`, `calendarActiveDateRanges`, `getCalendarDayFormat`).

:::

## Basic usage

Here's the minimal example to render a `Calendar` and a `Calendar.List`:

**`Calendar`**

<HStack spacing={24} alignItems="flex-start">

<div>
```tsx
import { Calendar, toDateId } from "@marceloterreiro/flash-calendar";
import { useState } from "react";
import { Text, View } from "react-native";

const today = toDateId(new Date());

export function BasicCalendar() {
  const [selectedDate, setSelectedDate] = useState(today);
  return (
    <View>
      <Text>Selected date: {selectedDate}</Text>
      <Calendar
        calendarActiveDateRanges={[
          {
            startId: selectedDate,
            endId: selectedDate,
          },
        ]}
        calendarMonthId={today}
        onCalendarDayPress={setSelectedDate}
      />
    </View>
  );
}
```
</div>
<Image img={basicCalendar} width={250}/>
</HStack>

**`Calendar.List`**

<HStack spacing={24} alignItems="flex-start">

<div>

```tsx
import { Calendar, toDateId } from "@marceloterreiro/flash-calendar";
import { useState } from "react";
import { Text, View } from "react-native";

const today = toDateId(new Date());

export function BasicCalendarList() {
  const [selectedDate, setSelectedDate] = useState(today);

  return (
    <View style={{ flex: 1 }}>
      <Text>Selected date: {selectedDate}</Text>
      <Calendar.List
        calendarActiveDateRanges={[
          {
            startId: selectedDate,
            endId: selectedDate,
          },
        ]}
        calendarInitialMonthId={today}
        onCalendarDayPress={setSelectedDate}
      />
    </View>
  );
}
```

</div>

<Image img={basicCalendarList} width={250} />

</HStack>

## Date range picker

Building a date range picker with Flash Calendar is easy thanks to the
[`useDateRange`](https://github.com/MarceloPrado/flash-calendar/blob/cd59ccfb60ccc3eb75a8e7ec2e347c6888be7091/packages/flash-calendar/src/hooks/useDateRange.ts#L68-L92)
hook:

<HStack spacing={24} alignItems="flex-start">

<div>

```tsx
import { Calendar, useDateRange } from "@marceloterreiro/flash-calendar";

export const CalendarListDateRange = () => {
  const {
    calendarActiveDateRanges,
    onCalendarDayPress,
    // Also available for your convenience:
    // dateRange, // { startId?: string, endId?: string }
    // isDateRangeValid, // boolean
    // onClearDateRange, // () => void
  } = useDateRange();
  return (
    <Calendar.List
      calendarActiveDateRanges={calendarActiveDateRanges}
      onCalendarDayPress={onCalendarDayPress}
    />
  );
};
```

</div>

<Image img={dateRangeCalendarList} width={250} />

</HStack>

## Localization and date formatting

Flash Calendar was built with a "bring your own date library" approach. This
means you can use your preferred date library to format how the dates, weeks and
months are displayed.

### Different locale

If you just need a different locale, use the `calendarFormatLocale` prop:

<HStack spacing={24} alignItems="flex-start">

<div>

```tsx
import { Calendar, toDateId } from "@marceloterreiro/flash-calendar";
import { useState } from "react";

const today = toDateId(new Date());

export function BrazilianCalendar() {
  const [selectedDate, setSelectedDate] = useState(today);
  return (
    <Calendar
      calendarActiveDateRanges={[
        {
          startId: selectedDate ?? undefined,
          endId: selectedDate ?? undefined,
        },
      ]}
      calendarMonthId={today}
      // highlight-next-line
      calendarFormatLocale="pt-BR"
      onCalendarDayPress={setSelectedDate}
    />
  );
}
```

</div>

<Image img={customLocale} width={250} />

</HStack>

### Custom date formatting

If you need full control over how the dates are displayed, use the
`getCalendarDayFormat`, `getCalendarMonthFormat` and `getCalendarWeekDayFormat`
props. They share the [same
signature](https://github.com/MarceloPrado/flash-calendar/blob/cd59ccfb60ccc3eb75a8e7ec2e347c6888be7091/packages/flash-calendar/src/hooks/useCalendar.ts#L108-L120)
and allow you to use your preferred date library:

<HStack spacing={24} alignItems="flex-start">

<div>

```tsx
import { Calendar, toDateId } from "@marceloterreiro/flash-calendar";
import { subMonths } from "date-fns";
import { format } from "date-fns/fp";

const threeMonthsAgo = subMonths(new Date(), 3);

export const CalendarCustomFormatting = () => {
  return (
    <Calendar
      calendarMonthId={toDateId(threeMonthsAgo)}
      // highlight-start
      getCalendarDayFormat={format("dd")}
      getCalendarMonthFormat={format("MMMM yyyy (LL/yyyy)")}
      getCalendarWeekDayFormat={format("E")}
      // highlight-end
      onCalendarDayPress={(dateId) => {
        console.log(`Clicked on ${dateId}`);
      }}
    />
  );
};
```

</div>

<Image img={customFormatting} width={250} />

</HStack>

#### Note on referential equality

Due to Flash Calendar's architecture, it's important to make your date
formatting functions stable. You should move them outside the component
scope (preferred) or memoize them with `useCallback`. Refer to [Issue
69](https://github.com/MarceloPrado/flash-calendar/issues/69) for more.

<HStack spacing={12}>
  <Admonition type="tip" title="DO">
    Make the formatting functions stable.

    ```tsx
    const today = toDateId(new Date());

    const Example = () => {
      return (
        <View style={{ flex: 1 }}>
          <Calendar
            calendarMonthId={today}
            getCalendarWeekDayFormat={formatWeekDay}
          />
        </View>
      );
    };

    const formatWeekDay = (date: Date) =>
      format(date, "EEEEEE");
    ```

  </Admonition>
  <Admonition type="danger" title="DON'T">
    Break referential equality by inlining the formatting functions.

    ```tsx
    <Calendar
      calendarMonthId={today}
      getCalendarWeekDayFormat={(date) =>
        // prettier-ignore
        format(date, "EEEEEE")
      }
    />
    ```

  </Admonition>
</HStack>

## Min, max and disabled dates

You can limit the range of selectable dates by using the `calendarMinDateId` and
`calendarMaxDateId` props. The `calendarDisabledDateIds` prop can be
used to disable specific dates.

This works for both `Calendar` and `Calendar.List`:

<HStack spacing={24} alignItems="flex-start">

<div>

```tsx
import { Calendar, toDateId } from "@marceloterreiro/flash-calendar";

const calendarDisabledDateIds = ["2024-03-14", "2024-03-15"];

export const CalendarCustomFormatting = () => {
  return (
    <Calendar
      // highlight-start
      calendarDisabledDateIds={calendarDisabledDateIds}
      calendarMaxDateId="2024-03-20"
      calendarMinDateId="2024-03-10"
      // highlight-end
      calendarMonthId="2024-03-01"
      onCalendarDayPress={(dateId) => {
        console.log(`Clicked on ${dateId}`);
      }}
    />
  );
};
```

</div>

<Image img={disabledDates} width={250} />

</HStack>

## Custom size and spacing

There are several props to tweak the spacings between the components. Check the [Anatomy](/fundamentals/customization#anatomy) section in the [Customization](/fundamentals/customization) docs for more:

<HStack spacing={24} alignItems="flex-start">

<div>

```tsx
import { Calendar } from "@marceloterreiro/flash-calendar";
import { View } from "react-native";

export const CalendarListCompact = () => {
  return (
    <View style={{ width: 300, flex: 1 }}>
      <Calendar.List
        calendarDayHeight={28}
        calendarMonthHeaderHeight={20}
        calendarRowHorizontalSpacing={0}
        calendarRowVerticalSpacing={4}
        calendarSpacing={10}
        onCalendarDayPress={(dateId) => console.log(`Pressed ${dateId}`)}
      />
    </View>
  );
};
```

</div>

<Image img={compact} width={250} />

</HStack>

## Bottom sheet

You can replace the base `FlashList` component by passing the
`CalendarScrollComponent` prop to `Calendar.List`. This is useful when you want
to use Flash Calendar in an Android [bottom sheet](https://github.com/gorhom/react-native-bottom-sheet).

<HStack spacing={24} alignItems="flex-start">

<div>

```tsx
import BottomSheet from "@gorhom/bottom-sheet";
import { Calendar } from "@marceloterreiro/flash-calendar";
import { FlashList } from "@shopify/flash-list";
import React, { useCallback, useMemo, useRef } from "react";
import { Platform, StyleSheet, View } from "react-native";

import { BottomSheetFlashList } from "./components/BottomSheetFlashList";

/**
 * iOS works fine with default flash list. Is better to keep it
 * since it's more performant.
 */
const SafeFlashList = Platform.select({
  android: BottomSheetFlashList,
  ios: FlashList,
});

export const BottomSheetCalendar = () => {
  const bottomSheetRef = useRef<BottomSheet>(null);
  const snapPoints = useMemo(() => ["25%", "50%"], []);

  return (
    <View style={styles.container}>
      <BottomSheet index={1} ref={bottomSheetRef} snapPoints={snapPoints}>
        <View style={styles.contentContainer}>
          <Calendar.List
            // highlight-next-line
            CalendarScrollComponent={SafeFlashList}
            calendarInitialMonthId="2024-02-01"
            onCalendarDayPress={(dateId) => console.log(`Pressed ${dateId}`)}
          />
        </View>
      </BottomSheet>
    </View>
  );
};
```

</div>

<video controls width={250}>
  <source src={bottomSheetAndroid} type="video/mp4" />
</video>

</HStack>

For a reference implementation of the `BottomSheetFlashList` component, check
the
[source](https://github.com/marceloprado/flash-calendar/blob/d832d72867d40c9b375c30aec9985b181c0a80f3/kitchen-sink/expo/src/components/BottomSheetFlashList/BottomSheetFlashList.tsx).
Bear in mind this isn't a very performant implementation. Contributions
welcomed!

## Two calendars in the same screen

To render more than one calendar in the same screen, use the
`calendarInstanceId` prop. This works for both `Calendar` and `Calendar.List`:

<HStack spacing={24} alignItems="flex-start">

<div>

```tsx
import { Calendar, useDateRange } from "@marceloterreiro/flash-calendar";

export const TwoCalendarsMounted = () => {
  const dateRangeOne = useDateRange();
  const dateRangeTwo = useDateRange();
  return (
    <VStack grow spacing={48}>
      <VStack grow spacing={4}>
        <Text>First calendar</Text>
        <Calendar
          calendarInstanceId="First"
          calendarMonthId="2024-08-01"
          {...dateRangeOne}
        />
      </VStack>
      <VStack grow spacing={4}>
        <Text>Second calendar</Text>
        <Calendar
          calendarInstanceId="Second"
          calendarMonthId="2024-08-01"
          {...dateRangeTwo}
        />
      </VStack>
    </VStack>
  );
};
```

</div>

<Image img={twoCalendarsMounted} width={250} />

</HStack>
